/// ****************************************************************************
/// Author:	        Robin Zhu
/// Create Date:	2012-1-4
/// Purpose: 		生成和执行支持Linq语法的SQL查询定义的类文件
/// ****************************************************************************
/// Modify By		Date			Remark
/// Robin           2012-8-15       在执行FirstOrDefault后显式关闭数据库连接（因为使用yield return以后，关闭连接的语句可能不会被执行）
/// ****************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;

namespace RB.DataAccess.Linq
{
    /// <summary>
    /// 生成和执行支持Linq语法的SQL查询定义的类
    /// </summary>
    public class SqlQueryableProvider : IQueryProvider
    {
        private Executor _executor;

        public SqlQueryableProvider(Executor executor)
        {
            _executor = executor;
        }

        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            return new SqlQueryable<TElement>(this, expression);
        }

        public IQueryable CreateQuery(Expression expression)
        {
            Type elementType = TypeSystem.GetElementType(expression.Type);
            try
            {
                return (IQueryable)Activator.CreateInstance(typeof(SqlQueryable<>).MakeGenericType(elementType), new object[] { this, expression });
            }
            catch (TargetInvocationException tie)
            {
                throw tie.InnerException;
            }
        }

        public TResult Execute<TResult>(Expression expression)
        {
            TResult result = default(TResult);
            Type type = typeof(TResult);
            if (type.IsClass && type != typeof(string))
            {
                result = _executor.ExecuteQuery<TResult>(expression).FirstOrDefault();
                _executor.CloseConnection();
            }
            else
            {
                result = _executor.ExecuteScalar<TResult>(expression);
            }
            return result;
        }

        public TResult Execute<TResult, TElement>(Expression expression)
            where TResult : IEnumerator<TElement>
        {
            var result = _executor.ExecuteQuery<TElement>(expression);
            return (TResult)result.GetEnumerator();
        }

        public object Execute(Expression expression)
        {
            Type elementType = TypeSystem.GetElementType(expression.Type);
            Type ienumtype = typeof(IEnumerator<>).MakeGenericType(elementType);
            MethodInfo method = this.GetType().GetMethod("Execute");
            MethodInfo genericMethod = method.MakeGenericMethod(ienumtype);
            return genericMethod.Invoke(this, new object[] { expression });
        }
    }
}
